//
//  Operation.m
//  alotOf
//
//  Created by Mac_Black_Mini on 2025/9/1.
//

#import "LinkOperation.h"
#import <NetworkExtension/NetworkExtension.h>
#define kKeychainServiceID @"com.CoderGin.VPNDemo.keychain.library"
#import "Tools.h"
#import <MJExtension/MJExtension.h>
#import "Report.h"
#import <FirebaseCore/FirebaseCore.h>
#import <FirebaseRemoteConfig/FirebaseRemoteConfig.h>
#import <ADSDK/SuperADLib.h>
#import "CoreDataManager.h"
#import "WLToastView.h"


@interface LinkOperation ()

@property (nonatomic, strong) NSArray <Node *>*nodes;
@property (nonatomic, strong) NEVPNManager *vpnManager;
@property (nonatomic, strong) VPNConfigInfo *info;
@property (nonatomic, strong) NETunnelProviderManager *tunnelManager;
/// 探测网络的任务数组
@property (nonatomic, strong) NSMutableArray <NSURLSessionDataTask *>*testNetTasks;
@property (nonatomic, assign) ConnectState connectState;
@property (nonatomic, strong) Node *selectNode;
/// 重试次数
@property (nonatomic, assign) NSInteger retryCount;
/// 下一个需要换线的 node
@property (nonatomic, assign) NSInteger nextIndex;
// 网络类型
@property (nonatomic, copy) NSString *netType;
/// 运营商名称
@property (nonatomic, copy) NSString *carrierName;
/// 开始链接时间
@property (nonatomic, assign) NSTimeInterval startConnectTime;
/// 开始测试网络时间
@property (nonatomic, assign) NSTimeInterval startTestTime;
/// 待上报的数组
@property (nonatomic, strong) NSMutableArray *reportModels;

/// 本地存储的remoteConfig
@property (nonatomic, copy) NSString *localNodes;
@property (nonatomic, copy) NSString *localReport;
@property (nonatomic, copy) NSString *localConfig;
@property (nonatomic, copy) NSString *advertising;
/// 连接中...
@property (nonatomic, assign) BOOL isConnecting;
@property (nonatomic, strong) VPNConfigInfo *config;
/// 第一次获取 RemoteConfig 成功
@property (nonatomic, assign) BOOL isRemoteConfigFirstFinished;
@end

NS_ASSUME_NONNULL_BEGIN

@implementation LinkOperation
#pragma mark - init
static LinkOperation *instance;
+ (instancetype)shared {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(!instance){
            instance = [[super allocWithZone:NULL] init];
            [instance preheating];
           
        }
    });
    return instance;
}
- (VPNConfigInfo *)getConfig{
    if (self.config == nil) {
        [self startVPN];
    }
    return self.config;
}



+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self shared];
}

+ (id)alloc {
    return [self allocWithZone:NULL];
}

#pragma mark - 公有方法
//链接vpn
-(void)linkVPNwithConfiginfo{
//    1.解析节点
    //远程配置 拉取
    [self a];
//    2.选择节点
//    映射节点初始化节点
//    3.链接
    [self startVPN];
//    [self startVPNWithNode:nil completion:^(NSError * _Nonnull) {
//        NSLog(@"error");
//            
//    }];

    
}

-(void)a{
    NSString *nodes = [[FIRRemoteConfig.remoteConfig configValueForKey:@"nodes"] stringValue];
    if (![self.localNodes isEqualToString:nodes]) {
        self.localNodes = nodes;
        
    }
    NSString *eventReportLinks = [[FIRRemoteConfig.remoteConfig configValueForKey:@"event_report_links"] stringValue];
    if (![self.localReport isEqualToString:eventReportLinks]) {
        self.localReport = eventReportLinks;
        
    }
    NSString *getConfigKey = [NSString stringWithFormat:@"%@_v2_manage_get_config", [NSBundle.mainBundle objectForInfoDictionaryKey:@"AppTag"]];
    NSString *getConfig = [[FIRRemoteConfig.remoteConfig configValueForKey:getConfigKey] stringValue];
    if (![self.localConfig isEqualToString:getConfig]) {
        self.localConfig = getConfig;
        
    }
    if ([Tools isEmpty:self.advertising]) {
        NSString *advertisingKey = [NSString stringWithFormat:@"%@_v2_manage_advertising", [NSBundle.mainBundle objectForInfoDictionaryKey:@"AppTag"]];
        self.advertising = [[FIRRemoteConfig.remoteConfig configValueForKey:advertisingKey] stringValue];
        [SuperADLib.shared loadRemoteDatas:@{@"get_config": getConfig, @"advertising": self.advertising}];
    }
    return;
}






///断掉vpn
-(void)sotpVPN{
    [self cancelTestNetwork];
    [self.tunnelManager.connection stopVPNTunnel];
}
#pragma mark - 私有方法

- (void)startVPNWithNode:(Node *)node completion:(nonnull void (^)(NSError * _Nonnull))completion {
    if (node) {
        self.selectNode = node;
        self.nextIndex = -1;
    } else {
        self.selectNode = self.nodes.firstObject;
        self.nextIndex = 0;
    }
    self.retryCount = 0;
    if (!self.selectNode) {
        completion([NSError errorWithDomain:NSBundle.mainBundle.bundleIdentifier code:0 userInfo:@{NSLocalizedDescriptionKey: @"nodes is nil"}]);
        return;
    }
    self.isConnecting = YES;
    self.connectState = ConnectStateConnecting;
    self.tunnelManager.enabled = YES;
    [self.tunnelManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
        if (error) {
            self.connectState = ConnectStateDisconnect;
            self.isConnecting = NO;
            completion(error);
            return;
        }
        [self.tunnelManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
            self.startConnectTime = NSDate.date.timeIntervalSince1970;
            if (self.tunnelManager.connection.status == NEVPNStatusDisconnected || self.tunnelManager.connection.status == NEVPNStatusInvalid) {
                [self startVPN];
            } else {
                [self.tunnelManager.connection stopVPNTunnel];
            }
        }];
    }];
}


/// 解密配置
- (void)decodeConfig {
    NSArray <NSString *>*nodeEncodeArray = [Tools stringToJson:self.localNodes];
    NSMutableArray <Node *>*nodeArray = [NSMutableArray array];
    [nodeEncodeArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *decodeStr = [Tools decryptAES:obj key:@"VXH2THdPBsHEp+XZ" iv:@"VXH2THdPBsHEp+XZ"];
        [nodeArray addObject:[Node mj_objectWithKeyValues:decodeStr context:[CoreDataManager sharedInstance].managedObjectContext]];
        [[CoreDataManager sharedInstance] saveContext];
    }];
  
    NSMutableArray *list =  [[CoreDataManager sharedInstance] queryDataWithEntityName:@"Node" predicate:nil sortDescriptors:@[] limit:nil offset:nil error:nil];
    
    NSLog(@"list.count   >> %ld",list.count);
    
    
    // 排序
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"weights" ascending:NO];
    [nodeArray sortUsingDescriptors:@[sortDescriptor]];
    self.nodes = nodeArray.copy;
    if (!self.selectNode) self.selectNode = self.nodes.firstObject;
    
    // event_report_links
    NSArray <NSString *>*reportEncodeArray = [Tools stringToJson:self.localReport];
    NSMutableArray <NSString *>*reportArray = [NSMutableArray array];
    [reportEncodeArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *decodeStr = [Tools decryptAES:obj key:@"VXH2THdPBsHEp+XZ" iv:@"VXH2THdPBsHEp+XZ"];
        [reportArray addObject:decodeStr];
    }];
    
    // CityVPN_v2_manage_get_config
    NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:self.localConfig options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSString *configJsonStr = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
    
    if(configJsonStr.length > 3){
        configJsonStr = [configJsonStr substringWithRange:NSMakeRange(1, configJsonStr.length - 2)];
        configJsonStr = [configJsonStr stringByReplacingOccurrencesOfString:@"\\" withString:@""];
        self.config = [VPNConfigInfo mj_objectWithKeyValues:configJsonStr];
    //    if (!self.config.sub_config) self.isVip = YES;
        NSLog(@"config-> open_ad: %@, wake_ad: %@, connected_ad: %@", self.config.open_ad, self.config.wake_ad, self.config.connected_ad);
        NSLog(@"config-> telegram_link: %@, bot_link: %@", self.config.telegram_link, self.config.bot_link);
    }
   
//    

//    
//    dispatch_async_safe_main(^{
//        [NSNotificationCenter.defaultCenter postNotificationName:kNotificationNameRemoteConfigDidUpdate object:@(!self.isRemoteConfigFirstFinished)];
//        self.isRemoteConfigFirstFinished = YES;
//    });
}





/// 加载 Sing-Box 配置文件
- (NSDictionary *)loadProfile {
    NSError *error;
    // 1. 获取 JSON 文件路径
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"config" ofType:@"json"];
    if (!filePath) {
        NSLog(@"JSON 文件未找到");
        return nil;
    }
    
    // 2. 读取文件数据
    NSData *jsonData = [NSData dataWithContentsOfFile:filePath];
    if (!jsonData) {
        NSLog(@"JSON 文件读取失败");
        return nil;
    }
    
 
    
    // 3. 解析 JSON 为 NSDictionary
    
    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
    if (error) {
        NSLog(@"JSON 解析失败: %@", error.localizedDescription);
        return nil;
    }
    
    return dictionary;
}

/// 开启 VPN
- (void)startVPN {
    
    
    NSError *error;
    NSMutableDictionary *profile = [[self loadProfile] mutableCopy];
    NSLog(@"vpn-> before profile: %@", [Tools dictToString:profile]);
    NSMutableArray *outbounds = [(profile[@"outbounds"] ?: @[]) mutableCopy];
    [outbounds removeLastObject];
    NSDictionary *nodeInfo = self.selectNode.nodeInfo;
    if (nodeInfo == nil) {
        [WLToastView showToast:@"没有拉取到节点信息，稍后"];
        return;
    }
    NSLog(@"vpn-> nodeInfo: %@", [Tools dictToString:nodeInfo]);
    [outbounds addObject:nodeInfo];
    profile[@"outbounds"] = outbounds;
    NSLog(@"vpn-> after profile: %@", [Tools dictToString:profile]);
    
    NSLog(@"vpn-> 第 %ld 次链接", self.retryCount);
  
    [self.tunnelManager.connection startVPNTunnelWithOptions:@{@"nodeInfo": nodeInfo, @"profile": [Tools dictToString:profile]} andReturnError:&error];
    if (error) {
        NSString *str=[NSString stringWithFormat:@"vpn-> 启动 VPN 错误：%@", error];
                       
                       
        
        [WLToastView showToast:str];
        Report *reportModel = [Report infoWithNode:self.selectNode];
        reportModel.connect_way = @"connect";
        reportModel.connect_result = @"0";
        reportModel.test_duration = @"";
        [self.reportModels addObject:reportModel];
        if (![self loadNextNode]) {
            [self sotpVPN];
            self.connectState = ConnectStateDisconnect;
            return;
        }
        [self startVPN];
    }
}

- (BOOL)loadNextNode {
    self.nextIndex++;
    if (self.nextIndex < self.nodes.count) {
        self.selectNode = self.nodes[self.nextIndex];
        return YES;
    }
    return NO;
}

///预热，获取之前所有配置vpn
-(void)preheating{
    //配置FIRRemoteConfig从远端拉取节点信息
    CoreDataManager *manager = [CoreDataManager sharedInstance];
   
    [self fetchRemoteConfig];
    [self loadVPNPreference];
    
}

/// 加载系统设置中的 VPN 配置
- (void)loadVPNPreference {
    [NETunnelProviderManager loadAllFromPreferencesWithCompletionHandler:^(NSArray<NETunnelProviderManager *> * _Nullable managers, NSError * _Nullable error) {
        
        ///若应用无配置，返回 nil 且无错误；若加载失败，返回 NSError 对象（如权限不足或配置损坏）
        if (error) {
            NSLog(@"error-> loadAllFromPreferences: %@", error);
            return;
        }
        
        
        if (managers.firstObject) {
            self.tunnelManager = managers.firstObject;
            if (self.tunnelManager.connection.status == NEVPNStatusConnected) self.connectState = ConnectStateConnected;
            return;
        }
        self.tunnelManager = [[NETunnelProviderManager alloc] init];
        NETunnelProviderProtocol *protocol = [[NETunnelProviderProtocol alloc] init];
        protocol.providerBundleIdentifier = [Tools.bundleId stringByAppendingString:@".PacketTunnel"];
        self.tunnelManager.protocolConfiguration = protocol;
        self.tunnelManager.localizedDescription = Tools.appName;
        self.tunnelManager.protocolConfiguration.serverAddress = Tools.appName;
        
        [self.tunnelManager saveToPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSLog(@"error-> saveToPreferences: %@", error);
                return;
            }
            [self.tunnelManager loadFromPreferencesWithCompletionHandler:^(NSError * _Nullable error) {
//                self.tunnelManager = manager;
                if (self.tunnelManager.connection.status == NEVPNStatusConnected) self.connectState = ConnectStateConnected;
            }];
        }];
    }];
}

#pragma mark - 配置

- (void)fetchRemoteConfig {
    // 设置缓存过期时间（秒）
    [FIRRemoteConfig remoteConfig];
    [FIRRemoteConfig.remoteConfig fetchWithExpirationDuration:0 completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
        if (status == FIRRemoteConfigFetchStatusSuccess) {
            NSLog(@"config-> Config fetched!");
            [FIRRemoteConfig.remoteConfig activateWithCompletion:^(BOOL changed, NSError * _Nullable error) {
                if (error) {
                    NSLog(@"config-> Activate error: %@", error.localizedDescription);
                    [self handleRemoteConfigError];
                } else {
                    // 配置已激活
                    [self handleRemoteConfig];
                    // 启动广告
                    //[self showAdWithConfig:[LinkOperation shared].config.open_ad];
                    // 添加变动监听
                    
                }
            }];
        } else {
            NSLog(@"config-> Config not fetched: %@", error.localizedDescription);
            [self handleRemoteConfigError];
        }
    }];
}


/// 处理配置
- (void)handleRemoteConfig {
    BOOL isNeedUpdate = NO;
    NSString *nodes = [[FIRRemoteConfig.remoteConfig configValueForKey:@"nodes"] stringValue];
    if (![self.localNodes isEqualToString:nodes]) {
        self.localNodes = nodes;
        isNeedUpdate = YES;
    }
    NSString *eventReportLinks = [[FIRRemoteConfig.remoteConfig configValueForKey:@"event_report_links"] stringValue];
    if (![self.localReport isEqualToString:eventReportLinks]) {
        self.localReport = eventReportLinks;
        isNeedUpdate = YES;
    }
    NSString *getConfigKey = [NSString stringWithFormat:@"%@_v2_manage_get_config", [NSBundle.mainBundle objectForInfoDictionaryKey:@"AppTag"]];
    NSString *getConfig = [[FIRRemoteConfig.remoteConfig configValueForKey:getConfigKey] stringValue];
    if (![self.localConfig isEqualToString:getConfig]) {
        self.localConfig = getConfig;
        isNeedUpdate = YES;
    }
    if ([Tools isEmpty:self.advertising]) {
        NSString *advertisingKey = [NSString stringWithFormat:@"%@_v2_manage_advertising", [NSBundle.mainBundle objectForInfoDictionaryKey:@"AppTag"]];
        self.advertising = [[FIRRemoteConfig.remoteConfig configValueForKey:advertisingKey] stringValue];
        [SuperADLib.shared loadRemoteDatas:@{@"get_config": getConfig, @"advertising": self.advertising}];
    }
    if (!isNeedUpdate) return;
    
    [self decodeConfig];
}

/// 处理获取配置错误的情况
- (void)handleRemoteConfigError {
    if (self.isRemoteConfigFirstFinished) return;
    if ([Tools isEmpty:self.localNodes]) {
        // 创建 AlertController
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Configuration loading failed!" preferredStyle:UIAlertControllerStyleAlert];
        // 添加按钮动作
        UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Reload" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self fetchRemoteConfig];
        }];
        // 将动作添加到Alert中
        [alert addAction:okAction];
        // 显示Alert
        [Tools.window.rootViewController presentViewController:alert animated:YES completion:nil];
    } else {
        [self decodeConfig];
        [self fetchRemoteConfig];
    }
}


/// 取消探测网络
- (void)cancelTestNetwork {
    [self.testNetTasks enumerateObjectsUsingBlock:^(NSURLSessionDataTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj cancel];
    }];
}

-(SuccessBlock)successBlock{
    return [_successBlock copy];
}



/// 设置钥匙串中的数据
- (BOOL)setKeychainWithString:(NSString*)string forIdentifier:(NSString*)identifier {
    NSMutableDictionary *searchDictionary = [self buildDefaultDictionaryForIdentity:identifier];
    NSData *keychainValue = [string dataUsingEncoding:NSUTF8StringEncoding];
    
    if ([self getDataReferenceInKeychainFromIdentifier:identifier] == nil) {
        [searchDictionary setObject:keychainValue forKey:(__bridge id)kSecValueData];
        OSStatus status = SecItemAdd((__bridge CFDictionaryRef)searchDictionary, NULL);
        if (status == errSecSuccess) {
            return YES;
        } else {
            return NO;
        }
    } else {
        NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
        [updateDictionary setObject:keychainValue forKey:(__bridge id)kSecValueData];
        OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary, (__bridge CFDictionaryRef)updateDictionary);
        if (status == errSecSuccess) {
            return YES;
        } else {
            return NO;
        }
    }
}

// 根据 identifier 获取钥匙串中的二进制数据
- (NSData *)getDataReferenceInKeychainFromIdentifier:(NSString *)identifier {
    
    return [self getDataInKeychainFromIdentifier:identifier returnReference:YES];
}
- (NSMutableDictionary *)buildDefaultDictionaryForIdentity:(NSString*)identifier {
    
    NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
    NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
    searchDictionary[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
    searchDictionary[(__bridge id)kSecAttrGeneric] = encodedIdentifier;
    searchDictionary[(__bridge id)kSecAttrAccount] = encodedIdentifier;
    searchDictionary[(__bridge id)kSecAttrService] = kKeychainServiceID;
    
    return searchDictionary;
}

// 根据 identifier 获取钥匙串中的数据
- (NSData *)getDataInKeychainFromIdentifier:(NSString *)identifier returnReference:(BOOL)referenceOnly {
    
    // get default dictionary
    NSMutableDictionary *dict = [self buildDefaultDictionaryForIdentity:identifier];
    
    // set for searching
    dict[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
    
    // need reference
    if (referenceOnly) {
        dict[(__bridge id)kSecReturnPersistentRef] = @YES;
    } else {
        dict[(__bridge id)kSecReturnData] = @YES;
    }
    
    // create result object
    CFTypeRef result = NULL;
    
    // Get result
    SecItemCopyMatching((__bridge CFDictionaryRef)dict, &result);
    
    // return result
    return (__bridge_transfer NSData *)result;
    
}

//拉取节点信息
-(void)getNodeInformation{
    
}

//上报节点错误
-(void)reportNodeInformation{
    
}

//探测网络
-(void)detectionNetwork{
    
}

//换线
-(void)changeWire{
    
}



@end

NS_ASSUME_NONNULL_END
